<?php
declare(strict_types=1);

namespace app;

use app\common\lib\HttpError;
use app\common\lib\ResponseJson;
use Error;
use ErrorException;
use InvalidArgumentException;
use ParseError;
use RedisException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\FuncNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\facade\Log;
use think\Request;
use think\Response;
use Throwable;
use TypeError;

/**
 * 应用异常处理类
 */
class ExceptionHandle extends Handle
{
    use ResponseJson;

    /**
     * 不需要记录信息（日志）的异常类列表
     *
     * @var array
     */
    protected $ignoreReport = [
        HttpException::class,
        HttpResponseException::class,
        ModelNotFoundException::class,
        DataNotFoundException::class,
        ValidateException::class,
    ];

    /**
     * 记录异常信息（包括日志或者其它方式记录）
     *
     * @access public
     *
     * @param Throwable $exception
     *
     * @return void
     */
    public function report(Throwable $exception): void
    {
        // 使用内置的方式记录异常日志
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @access public
     *
     * @param Request $request
     * @param Throwable $e
     *
     * @return Response
     */
    public function render($request, Throwable $e): Response
    {
        // 接管异常
        if (strtolower(app('http')->getName()) == 'api' || strtolower(app('http')->getName()) == 'admin') {
            $fatal = [
                'debug' => [
                    'error' => $e->getMessage(),
                    'line'  => $e->getLine(),
                    'file'  => $e->getFile(),
                ]
            ];
            // 记录日志
            $fatal = [];
            Log::record('【错误信息】' . $e->getMessage() . "\r\n文件地址：" . $e->getFile() . "\r\n错误行数：" . $e->getLine());

            // 添加自定义异常处理机制
            if ($e instanceof HttpException) {
                $http_code = (int)$e->getStatusCode();

                switch ($http_code) {
                    case '404';
                        $result = $this->jsonFailData(HttpError::NOT_FOUND_ERR[1], [], HttpError::NOT_FOUND_ERR[0], HttpError::NOT_FOUND_ERR[2], $fatal);
                        break;
                    default;
                        $result = $this->jsonFailData($e->getMessage(), [], $e->getCode(), $http_code, $fatal);
                        break;
                }

                return $result;
            } elseif ($e instanceof ErrorException) {
                return $this->jsonFailData($e->getMessage(), [], HttpError::SERVER_INTERNAL_ERROR[0], HttpError::SERVER_INTERNAL_ERROR[2], $fatal);
            } elseif ($e instanceof ParseError || $e instanceof Error || $e instanceof TypeError || $e instanceof \think\exception\ErrorException || $e instanceof InvalidArgumentException || $e instanceof DbException) {
                return $this->jsonFailData(HttpError::SERVER_INTERNAL_ERROR[1], [], HttpError::SERVER_INTERNAL_ERROR[0], HttpError::SERVER_INTERNAL_ERROR[2], $fatal);
            } elseif ($e instanceof RedisException) {
                return $this->jsonFailData(HttpError::REDIS_ERR[1], [], HttpError::REDIS_ERR[0], HttpError::REDIS_ERR[2], $fatal);
            } elseif ($e instanceof ValidateException) {
                return $result = $this->jsonFailData($e->getMessage(), [], HttpError::NOT_PARAM_ERR[0], HttpError::NOT_PARAM_ERR[2], $fatal);
            } elseif ($e instanceof FuncNotFoundException) {
                return $result = $this->jsonFailData(HttpError::NOT_FOUND_ERR[1], [], HttpError::NOT_FOUND_ERR[0], HttpError::NOT_FOUND_ERR[2], $fatal);
            }
        }

        //halt($e);
        // 其他错误交给系统处理
        return parent::render($request, $e);
    }
}